import re

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.remote.webelement import WebElement
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.select import Select
from selenium.webdriver.support.wait import WebDriverWait


class BrowserType:
    Chrome = 'Chrome'
    Firefox = 'Firefox'
    Ie = 'Ie'
    Edge = 'Edge'


class SeleniumHelper(object):
    __driverType = None
    __driver = None
    __mainHandler = None
    __implicitly_wait: float = None

    @staticmethod
    def Chrome(options: list[str] = None):
        return SeleniumHelper(BrowserType.Chrome, options)

    @staticmethod
    def Firefox(options: list[str] = None):
        return SeleniumHelper(BrowserType.Firefox, options)

    @staticmethod
    def Ie(options: list[str] = None):
        return SeleniumHelper(BrowserType.Ie, options)

    @staticmethod
    def Edge(options: list[str] = None):
        return SeleniumHelper(BrowserType.Edge, options)

    def __init__(self, broswerType: str, options: list[str] = None):
        self.__driverType = broswerType.upper()

        def addOptions(opt, options: list[str]):
            if not options or options.__len__() == 0:
                return None
            prefs: dict = {}
            for iOption in options:
                iOption = iOption.replace(re.search('#.*#', iOption)[0], "")
                opt.add_argument(iOption)
                if iOption == '--disable-images':
                    prefs['images'] = 2
            opt.add_experimental_option('prefs', {
                'profile.default_content_setting_values': prefs
            })

        if self.__driverType == 'CHROME' or self.__driverType == 'GC':
            opt = webdriver.ChromeOptions()
            addOptions(opt, options)
            self.__driver = webdriver.Chrome(options=opt)
        elif self.__driverType == 'FIREFOX' or self.__driverType == 'FF':
            opt = webdriver.FirefoxOptions()
            addOptions(opt, options)
            self.__driver = webdriver.Firefox(options=opt)

        elif self.__driverType == 'IE':
            opt = webdriver.IeOptions()
            addOptions(opt, options)
            self.__driver = webdriver.Ie(options=opt)

        elif self.__driverType == 'EDGE':
            opt = webdriver.IeOptions()
            addOptions(opt, options)
            self.__driver = webdriver.Chrome(options=opt)
        else:
            raise Exception(f'暂不支持浏览器：{broswerType}')
        if self.__driver is None:
            raise Exception(f'暂不支持浏览器：{broswerType}')
        self.__mainHandler = self.__driver.current_window_handle

    def BROWSER_maximize_window(self) -> None:
        self.__driver.maximize_window()

    def BROWSER_set_window_size(self, w: float, h: float) -> None:
        self.__driver.set_window_size(w, h)

    def BROWSER_getUrl(self, url: str, force: bool = True) -> None:
        if not force and self.__driver.current_url == url:
            return
        self.__driver.get(url)

    def BROWSER_switch_to_window(self, idx: int) -> None:
        windows = self.__driver.window_handles
        self.__driver.switch_to.window(windows[idx])

    def quit(self):
        self.__driver.quit()

    def BROWSER_SET_implicitly_wait(self, time: float) -> None:
        self.__implicitly_wait = time
        self.__driver.implicitly_wait(time)

    def BROWSER_get_cookies(self):
        self.__driver.get_cookies()

    def BROWSER_current_url(self):

        return self.__driver.current_url

    def BROWSER_wait(self, method: str, timeout: float, frequency: float, until: bool, args: list):

        if until:
            u = WebDriverWait(self.__driver, timeout, frequency).until
        else:
            u = WebDriverWait(self.__driver, timeout, frequency).until_not

        func = getattr(EC, method)

        if not args or args.__len__() == 0:
            result = u(func())
        else:
            result = u(func(*args))
        return result

    def WEB_select(self, elem: WebElement, selectBy: str, selectContent: any):
        sl = Select(elem)

        selectBy = selectBy.lower()
        if selectBy == 'index':
            fn = sl.select_by_index
        elif selectBy == 'value':
            fn = sl.select_by_value
        elif selectBy == 'visible_text':
            fn = sl.select_by_visible_text
        fn(selectContent)

    def WEB_waitElem(self, options: dict, by: str, path: str):
        return self.BROWSER_wait(options.get('method'), options.get('timeout', 10), options.get('frequency', 0.5),
                                 options.get('until', 'until'), [(by, path)])

    def elemFind(self, by: str, path: str) -> WebElement:
        by = by or By.XPATH
        return self.__driver.find_element(by, path)

    def elemFindBy(self):
        self.__driver.find_element_by_partial_link_text()
        self.__driver.find_element_by_css_selector()

    def WEB_switch_to_frame(self, by: str, path: str):
        elem = self.elemFind(by, path)
        self.__driver.switch_to.frame(elem)

    def WEB_switch_to_default_content(self):
        self.__driver.switch_to.default_content()

    def WEB_scrollIntoView(self, elem: WebElement):
        self.__driver.execute_script("arguments[0].scrollIntoView(false);", elem)

    def BROSWER_screenshot(self):
        return self.__driver.get_screenshot_as_png()

    def BROWSER_close(self):
        return self.__driver.close()
